/*
 * 
 * Copyright 2010 David H Pollack
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 * 
 * 
 */

package com.dhpollack.rotogss.servlets;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.Transaction;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.dhpollack.rotogss.data.AppConfig;
import com.dhpollack.rotogss.data.RotoGSSTeams;
import com.dhpollack.rotogss.data.RotoGSSUsers;
import com.dhpollack.rotogss.data.YahooGames;
import com.dhpollack.rotogss.data.YahooGamesStats;
import com.dhpollack.rotogss.data.YahooLeagues;
import com.dhpollack.rotogss.helper.AppHelper;
import com.dhpollack.rotogss.helper.PMF;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.gdata.client.authn.oauth.GoogleOAuthParameters;
import com.google.gdata.client.authn.oauth.OAuthException;
import com.google.gdata.client.authn.oauth.OAuthHmacSha1Signer;
import com.google.gdata.client.docs.DocsService;
import com.google.gdata.client.spreadsheet.FeedURLFactory;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.MediaContent;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.docs.DocumentEntry;
import com.google.gdata.data.docs.DocumentListEntry;
import com.google.gdata.data.docs.FolderEntry;
import com.google.gdata.data.docs.PresentationEntry;
import com.google.gdata.data.docs.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.Column;
import com.google.gdata.data.spreadsheet.Data;
import com.google.gdata.data.spreadsheet.Header;
import com.google.gdata.data.spreadsheet.TableEntry;
import com.google.gdata.data.spreadsheet.Worksheet;
import com.google.gdata.data.spreadsheet.WorksheetEntry;
import com.google.gdata.util.ResourceNotFoundException;
import com.google.gdata.util.ServiceException;

/**
 * @author davidpl
 *
 */
public class GMakeSpreadServlet extends HttpServlet {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -4024085697805809534L;

	private DocsService docsClient = new DocsService("dhpollack-RotoGSS-v1");
	
	private SpreadsheetService spreadClient = new SpreadsheetService("dhpollack-RotoGSS-v1");
	
	private static final AppConfig appConfig = AppHelper.get();
	
	private static final String BASE_DOCS_URL = "https://docs.google.com/feeds/default/private/full/";
	
	private static final String BASE_SS_URL = "https://spreadsheets.google.com/feeds/";
	
	public void doGet(HttpServletRequest req, HttpServletResponse resp) 
    throws ServletException, IOException {
		doPost(req, resp);
	}
	
	public void doPost(HttpServletRequest req, HttpServletResponse resp) 
    throws ServletException, IOException {

		PersistenceManager pm = PMF.get().getPersistenceManager();
		
		String user = req.getParameter("user");
		
		if(user == null) {
			log("No user set");
			return;
		}
		
		boolean deleteTable = (req.getParameter("force_delete") != null && req.getParameter("force_delete").toLowerCase().equals("true")) ? true : false;
		
		String team = req.getParameter("team");
		
		if(team == null) {
			log("No team set");
			return;
		}

		/*
		 * Get User Information and set Google OAuth parameters
		 * for subsequent calls to the Documents service.
		 * 
		 */
		RotoGSSUsers gss_user;
		try {
			Key user_key = new KeyFactory.Builder(
					RotoGSSUsers.class.getSimpleName(), user).getKey();
			gss_user = pm.getObjectById(RotoGSSUsers.class, user_key);
			setOAuthCredentials(gss_user);
		} catch (JDOObjectNotFoundException e) {
			log("User Not Found: " + user);
			e.printStackTrace();
			return;
		} catch (OAuthException e) {
			log("OAuth Exception for: " + user);
			e.printStackTrace();
			return;
		}
		
		/*
		 * Get RotoGSS Team Info
		 */
		
		RotoGSSTeams gss_team = null;
		try { 
			Key team_key = new KeyFactory.Builder(RotoGSSUsers.class.getSimpleName(), user)
										 .addChild(RotoGSSTeams.class.getSimpleName(), team)
										 .getKey();
			gss_team = pm.getObjectById(RotoGSSTeams.class, team_key);
		} catch(JDOObjectNotFoundException e) {
			log("Team Not Found: " + team);
			e.printStackTrace();
			return;
		}
		
		DocumentListEntry leagueSpreadsheetEntry = null;
		if(gss_team.getGoogleLeagueSpreadsheet() == null) {
			/*
			 * Create the main folder for this webapp within the user's 
			 * Google Docs.
			 */
			DocumentListEntry mainFolder = null;
			if(gss_user.getGoogleMainFolder() == null) {
				try {
					mainFolder = createFolder("RotoGSS");
					gss_user = saveMainFolderResourceId(pm, gss_user, mainFolder);
				} catch(ServiceException e) {
					log("ServiceException During Main Folder Creation");
					e.printStackTrace();
				}
			} else {
				log("Found Main Folder");
				String resource_id = gss_user.getGoogleMainFolder();
				try {
					mainFolder = getDocumentByResourceId(resource_id);
				} catch (ServiceException e) {
					log("ServiceException During Getting Main Folder");
					e.printStackTrace();
					
				}
			}
			
			// TODO Create Google Docs Folder for each Yahoo game
			DocumentListEntry gameFolder = null;
			if(gss_team.getGoogleGameFolder() == null) {
				try {
					String game_title = getGameTitle(team);
					log(game_title);
					if(game_title != null) {
						String folder_uri = ((MediaContent) mainFolder.getContent()).getUri();
						gameFolder = createFolder(game_title, new URL(folder_uri));
						gss_team = saveGameFolderResourceId(pm, gss_team, gameFolder);
					} else {
						log("Game Title was null");
					}
				} catch(ServiceException e) {
					log("ServiceException During Getting Main Folder");
					e.printStackTrace();
				}
			} else {
				log("Found Game Folder");
				String resource_id = gss_team.getGoogleGameFolder();
				try {
					gameFolder = getDocumentByResourceId(resource_id);
				} catch (ServiceException e) {
					log("ServiceException During Getting Main Folder");
					e.printStackTrace();
				}
			}
			
			try {
				String folder_uri = ((MediaContent) gameFolder.getContent()).getUri();
				leagueSpreadsheetEntry = createNewDocument(team, "spreadsheet", 
															new URL(folder_uri));
				// Create Worksheets
				List<String> new_sheets = new ArrayList<String>();
				createRotoWorksheets(new SpreadsheetEntry(leagueSpreadsheetEntry), new_sheets);

				gss_team = saveSpreadsheetResourceId(pm, gss_team, leagueSpreadsheetEntry);
			} catch(ServiceException e) {
				log("ServiceException During Spreadsheet Creation");
				e.printStackTrace();
			}
		} else {
			log("Found Spreadsheet");
			String resource_id = gss_team.getGoogleLeagueSpreadsheet();
			try {
				leagueSpreadsheetEntry = getDocumentByResourceId(resource_id);
			} catch(ServiceException e) {
				log("ServiceException During Getting Spreadsheet: " + e.toXmlErrorMessage());
				e.printStackTrace();
				
			}
		}
		
		
		
		// Create Table within Spreadsheet
		String spreadsheet_id = leagueSpreadsheetEntry.getDocId();
		TableEntry tableEntry = null;
		if(gss_team.getGoogleTableId() == null) {

			// Grab table headers
			List<String> headers = getTableHeaders(team);
			
			try {
				tableEntry = createTableEntry(spreadsheet_id, "Standings", "Standings", headers);
				gss_team = saveTableResourceId(pm, gss_team, tableEntry);
			} catch (ServiceException e) {
				log("ServiceException Creating Table: " + e.toString());
				
				e.printStackTrace();
			}


		} else {
			log("Found Table");
			String table_id = gss_team.getGoogleTableId();
			try {
				tableEntry = getTableById(table_id);
				if(deleteTable) tableEntry.delete();
			} catch(ServiceException e) {
				log("ServiceException During Getting Table\n Table Id: " + table_id);
				log("ServiceException Getting Table: " + e.toString());
				e.printStackTrace();
			}
		}
		

	}

	/********************** End doPost *********************************/
	
	private void createRotoWorksheets(SpreadsheetEntry spreadsheetEntry, List<String> sheets)
	throws IOException, ServiceException {

		if(sheets.isEmpty()) {
			sheets.add("Standings");
			sheets.add("Transactions");
			sheets.add("Draft");
			sheets.add("Legend");
			sheets.add("Players");
			sheets.add("Messages");
		}
		
		for(String sheet: sheets) {
			WorksheetEntry worksheet = new WorksheetEntry();
			worksheet.setTitle(new PlainTextConstruct(sheet));
			worksheet.setRowCount(200);
			worksheet.setColCount(30);

			URL worksheetFeedUrl = spreadsheetEntry.getWorksheetFeedUrl();
			spreadClient.insert(worksheetFeedUrl, worksheet);

		}
		
	}

	private RotoGSSTeams saveTableResourceId(PersistenceManager pm,
			RotoGSSTeams gss_team, TableEntry tableEntry) {
		Transaction tx = pm.currentTransaction();

		//int tableid_slash = tableEntry.getId().lastIndexOf("/");
		//String resource_id = tableEntry.getId().substring(tableid_slash+1);

		String resource_id = tableEntry.getId();

		try {
			tx.begin();
			gss_team.setGoogleTableId(resource_id);
			pm.makePersistent(gss_team);
			tx.commit();
		} finally {
			if(tx.isActive()) {
				tx.rollback();
			}
		}
		
		return gss_team;
	}

	private List<String> getTableHeaders(String team) {
		List<String> r = new ArrayList<String>();
		
		PersistenceManager pm = PMF.get().getPersistenceManager();
		// Processing for game key.  Will be replaced with game parse
		StringBuilder s = new StringBuilder();
		String regex = "\\.";
		Pattern numSplit = Pattern.compile(regex);
		String[] m = numSplit.split(team);
		Integer game_id = Integer.parseInt(m[0]);
		s.append(m[0]);
		s.append(".");
		s.append(m[1]);
		s.append(".");
		s.append(m[2]);
		String league_id = s.toString();
		
		Key key = new KeyFactory.Builder(YahooGames.class.getSimpleName(), game_id)
								.addChild(YahooLeagues.class.getSimpleName(), league_id)
								.getKey();
		
		try {
			YahooLeagues league = pm.getObjectById(YahooLeagues.class, key);
			List<Key> stat_keys = league.getLeagueStats();
			r.add("Team Key");
			r.add("Team Name");
			r.add("Date");
			r.add("Rank");
			r.add("Total");
			r.add("Change");
			for(Key stat_key : stat_keys) {
				YahooGamesStats stat = pm.getObjectById(YahooGamesStats.class, stat_key);
				r.add(stat.getStatDisplayName());
			}
			return r;
		} catch(JDOObjectNotFoundException e) {
			log("League Not Found: " + key);
		}
		
		return null;
	}

	private RotoGSSTeams saveSpreadsheetResourceId(PersistenceManager pm,
			RotoGSSTeams gss_team, DocumentListEntry spreadsheet) {
		// TODO Auto-generated method stub
		Transaction tx = pm.currentTransaction();

		String resource_id = spreadsheet.getResourceId();
		try {
			tx.begin();
			gss_team.setGoogleLeagueSpreadsheet(resource_id);
			pm.makePersistent(gss_team);
			tx.commit();
		} finally {
			if(tx.isActive()) {
				tx.rollback();
			}
		}
		
		return gss_team;
	}

	private RotoGSSTeams saveGameFolderResourceId(PersistenceManager pm,
			RotoGSSTeams gss_team, DocumentListEntry folder) {
		Transaction tx = pm.currentTransaction();
		
		String resource_id = folder.getResourceId();
		
		try {
			tx.begin();
			gss_team.setGoogleGameFolder(resource_id);
			pm.makePersistent(gss_team);
			tx.commit();
		} finally {
			if(tx.isActive()) {
				tx.rollback();
			}
		}
		
		return gss_team;
	}

	private String getGameTitle(String team) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		
		String r = null;
		
		// Processing for game key.  Will be replaced with game parse
		String regex = "\\.";
		Pattern numSplit = Pattern.compile(regex);
		String[] m = numSplit.split(team);
		Integer game_id = Integer.parseInt(m[0]);

		Key key = new KeyFactory.Builder(YahooGames.class.getSimpleName(), game_id).getKey();
		try {
			YahooGames game = pm.getObjectById(YahooGames.class, key);
			r = game.getCode().toUpperCase() + " - " + game.getSeason();
		} catch(JDOObjectNotFoundException e) {
			throw e;
		}
		
		
		return r;
	}

	private DocumentListEntry getDocumentByResourceId(String resource_id)
			throws IOException, ServiceException {
		URL url = new URL(BASE_DOCS_URL + resource_id);
		DocumentListEntry entry = null;
		try {
			entry = docsClient.getEntry(url, DocumentListEntry.class);
		} catch (ResourceNotFoundException e) {
			log("Google Doc Not Found");
			entry = null;
		}
		return entry;
	}

	private TableEntry getTableById(String table_id)
	throws IOException, ServiceException {
		// TODO Auto-generated method stub
		TableEntry entry = new TableEntry();
		
		URL tableUrl = new URL(table_id);
		try {
			entry = spreadClient.getEntry(tableUrl, TableEntry.class);
		} catch(ResourceNotFoundException e) {
			log("Google Doc Not Found");
			entry = null;
		}
		return entry;
	}

	private TableEntry getTableById(String spreadsheet_id, String table_id)
	throws IOException, ServiceException {
		// TODO Auto-generated method stub
		TableEntry entry = new TableEntry();
		
		URL tableUrl = new URL(BASE_SS_URL + spreadsheet_id + "/tables/" + table_id);
		try {
			entry = spreadClient.getEntry(tableUrl, TableEntry.class);
		} catch(ResourceNotFoundException e) {
			log("Google Doc Not Found");
			entry = null;
		}
		return entry;
	}

	private RotoGSSUsers saveMainFolderResourceId(PersistenceManager pm,
			RotoGSSUsers user, DocumentListEntry folder) {
		
		Transaction tx = pm.currentTransaction();
		
		String resource_id = folder.getResourceId();
		
		try {
			tx.begin();
			user.setGoogleMainFolder(resource_id);
			pm.makePersistent(user);
			tx.commit();
		} finally {
			if(tx.isActive()) {
				tx.rollback();
			}
		}
		
		return user;
		
	}

	private void setOAuthCredentials(RotoGSSUsers gss_user) throws OAuthException {

		GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
		oauthParameters.setOAuthConsumerKey(appConfig.getGoogleConsumerKey());
		oauthParameters.setOAuthConsumerSecret(appConfig.getGoogleConsumerSecret());
		oauthParameters.setOAuthToken(gss_user.getGoogleAccessToken());
		oauthParameters.setOAuthTokenSecret(gss_user.getGoogleAccessTokenSecret());

		try {
			docsClient.setOAuthCredentials(oauthParameters, new OAuthHmacSha1Signer());
			spreadClient.setOAuthCredentials(oauthParameters, new OAuthHmacSha1Signer());
		} catch (OAuthException e) {
			log("OAuthException: " + e.toString());
			e.printStackTrace();
			throw e;
		}
		
	}
	
	private DocumentListEntry createFolder(String title, URL uri)
	throws IOException, ServiceException {
		
		DocumentListEntry newEntry = new FolderEntry();
		newEntry.setTitle(new PlainTextConstruct(title));
		log("Creating New Folder");
		return docsClient.insert(uri, newEntry);

	}

	private DocumentListEntry createFolder(String title)
	throws IOException, ServiceException {
		return createFolder(title, new URL(BASE_DOCS_URL));
	}
	
    private DocumentListEntry createNewDocument(String title, String type, URL uri)
    throws IOException, ServiceException {

    	DocumentListEntry newEntry = null;
    	if (type.equals("document")) {
    		newEntry = new DocumentEntry();
    	} else if (type.equals("presentation")) {
    		newEntry = new PresentationEntry();
    	} else if (type.equals("spreadsheet")) {
    		newEntry = new SpreadsheetEntry();
    	}
    	newEntry.setTitle(new PlainTextConstruct(title));

    	return docsClient.insert(uri, newEntry);
    }

    private DocumentListEntry createNewDocument(String title, String type)
        throws MalformedURLException, IOException, ServiceException {
      return createNewDocument(title, type, new URL(BASE_DOCS_URL));
    }
    
    private TableEntry createTableEntry(String spreadsheet, String sheet, String title, List<String> headers)
    throws IOException, ServiceException {
		
		FeedURLFactory factory = new FeedURLFactory("https://spreadsheets.google.com");
		URL tableFeedUrl = factory.getTableFeedUrl(spreadsheet);
		
		URL tableFeedUrlManual = new URL("https://spreadsheets.google.com/feeds/" + spreadsheet + "/tables/");


    	TableEntry tableEntry = new TableEntry();
		
		log("Table Feed URL: \n" + tableFeedUrl.toString() + "\n" + tableFeedUrlManual.toString());

		// Specify a basic table:
		tableEntry.setTitle(new PlainTextConstruct(title));
		tableEntry.setWorksheet(new Worksheet(sheet));
		tableEntry.setHeader(new Header(1));

		// Specify columns in the table, start row, number of rows.
		Data tableData = new Data();
		tableData.setNumberOfRows(0);
		// Start row index cannot overlap with header row.
		tableData.setStartIndex(2);
		
		int header_count = headers.size();
		char letter = 'A';
		for(int i = 0; i < header_count; i++) {
			log(String.valueOf(letter) + ": " + headers.get(i));
			Column col = new Column(String.valueOf(letter), headers.get(i));

			tableData.addColumn(col);
			letter++;
		}
		tableEntry.setData(tableData);

		return spreadClient.insert(tableFeedUrl, tableEntry);


    }





}
